#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/un.h>
#include <pthread.h>
#include <limits.h>
#include <errno.h>

#include "usocket.h"

int usocket_recv(int s, void *buf, size_t len)
{
	ssize_t ret;
	
	while(1)
	{
		ret = recv(s, buf, len, MSG_WAITALL);
		if((ret < 0) &&
           (errno == EAGAIN ||
            errno == EWOULDBLOCK ||
            errno == EINTR))
		{
			continue;
		}
		break;
	}

    return ret;
}

int usocket_send(int s, void *buf, size_t len)
{
	ssize_t ret;
    ssize_t cnt = 0;
	
	while (len - cnt)
	{
		ret = send(s, buf + cnt, (len - cnt), MSG_NOSIGNAL);
        if (ret < 0)
        {
    		if(errno == EAGAIN ||
                errno == EWOULDBLOCK ||
                errno == EINTR)
    		{
    			continue;
    		}
            else
                break;
        }
        cnt += ret;
	}

    return (ret < 0)? ret: cnt;
}

/******************************************************************************
 * Function name: usocket_connect
 * Description:	  connect to server
 * Parameter:     id    input  const char *
 * Return value:  sockfd
 * Error code:
 *****************************************************************************/
int usocket_connect(const char *id)
{
    int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket create failed: "); 
		return -1;
    }

	struct sockaddr_un addr;

    addr.sun_family = AF_UNIX;
    addr.sun_path[0] = '\0';
    strncpy(&addr.sun_path[1], id, sizeof(addr.sun_path) - 2);

    int result = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));

    if(result == -1)
	{        
		perror("connect failed: ");        
		return -1;   
	}

    return sockfd;
}

/******************************************************************************
 * Function name: usocket_listen
 * Description:	  listen
 * Parameter:     id  input  const int32_t
 * Return value:  listenfd
 * Error code:
 *****************************************************************************/
int usocket_listen(const char *id)
{
	int ret;
    int serv_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (serv_sockfd == -1)
    {
        perror("socket create failed: "); 
		return -1;
    }

    struct sockaddr_un serv_addr;

    serv_addr.sun_family = AF_UNIX;
    serv_addr.sun_path[0] = '\0';
    strncpy(&serv_addr.sun_path[1], id, sizeof(serv_addr.sun_path) - 2);

    ret = bind(serv_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

    if (ret == -1)
    {
        perror("bind failed: "); 
        return -1;
    }

    ret = listen(serv_sockfd, 5);

    if (ret == -1)
    {
        perror("listen failed: "); 
        return -1;
    }

    return serv_sockfd;
}

/******************************************************************************
 * Function name: usocket_accept
 * Description:	  accept
 * Parameter:     serv_sockfd  input  int
 * Return value:  cli_sockfd
 * Error code:
 *****************************************************************************/
int usocket_accept(int serv_sockfd)
{
    struct sockaddr_un cli_addr = {0};

    socklen_t clilen = sizeof(cli_addr);

    int cli_sockfd = accept(serv_sockfd, (struct sockaddr *) &cli_addr, &clilen);

    if (cli_sockfd == -1)
    {
        perror("accept failed: "); 
        return -1;
    }

    return cli_sockfd;
}

void create_thread(Thread_Handle handle, void *arg, size_t stacksize)
{
	pthread_t t;
    pthread_attr_t attr;    
    pthread_attr_init(&attr);
    pthread_attr_setstacksize(&attr, stacksize);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&t, &attr, handle, arg);
    pthread_attr_destroy(&attr);
}

//client
/*
int main()
{  
    return 0;
} 
*/
